package org.Reflection;

import org.apache.logging.log4j.core.tools.picocli.CommandLine;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class GetClass {
    static void printClassInfo(Class cls) {
        System.out.println("---------------------printClassInfo---------------------");
        System.out.println("Class name: " + cls.getName());
        System.out.println("Simple name: " + cls.getSimpleName());
        if (cls.getPackage() != null) {
            System.out.println("Package name: " + cls.getPackage().getName());
        }
        System.out.println("is interface: " + cls.isInterface());
        System.out.println("is enum: " + cls.isEnum());
        System.out.println("is array: " + cls.isArray());
        System.out.println("is primitive: " + cls.isPrimitive());
        System.out.println("************************printClassInfo***********************");
    }

    public static void printCommonClass() {
        System.out.println("printCommonClass begin.");
        printClassInfo("".getClass());
        printClassInfo(Runnable.class);
        printClassInfo(java.time.Month.class);
        printClassInfo(String[].class);
        printClassInfo(int.class);
        printClassInfo(Boolean.class);
        printClassInfo(boolean.class);
        printClassInfo(long.class);
        printClassInfo(float.class);
        try {
            printClassInfo(Class.forName("java.util.Random"));
        } catch (ClassNotFoundException exception) {
            System.out.println("java.util.Random not found");
        } finally {
            System.out.println("printCommonClass end.");
        }
    }

    public static void getField() {
        Class stdClass = Student.class;
        try {
            // 获取public字段"score":
            System.out.println(stdClass.getField("score"));
            // 获取继承的public字段"name":
            System.out.println(stdClass.getField("name"));
            // 获取private字段"grade":
            System.out.println(stdClass.getDeclaredField("grade"));
            Field grade = stdClass.getDeclaredField("grade");
            int m = grade.getModifiers();
            System.out.printf("grade modifiers %X", m);
        } catch (NoSuchFieldException exception) {
            System.out.println("Student get Field fail.");
        } finally {
            System.out.println("getField ok.");
        }
    }

    public static void getFieldValue() {
        Object p = new Person("Xiao Ming");
        Class c = p.getClass();
        try {
            Field f = c.getDeclaredField("name");
            Object value = f.get(p);
            f.setAccessible(true);
            System.out.println("Person name " + value);
        } catch (NoSuchFieldException exception) {

        } catch (IllegalAccessException exception) {

        }
    }

    public static void getMethod() {
        try {
            Method m = Person.class.getMethod("hello");
            Student student = new Student("xiaohong", 100, 1);
            m.invoke(student);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException exception) {

        }

    }

    public static void getConstructor() {
        System.out.println("getConstructor begin");
        // 获取构造方法Integer(int):
        try {
            Constructor cons1 = Integer.class.getConstructor(int.class);
            // 调用构造方法:
            Integer n1 = (Integer) cons1.newInstance(123);
            System.out.println(n1);

            // 获取构造方法Integer(String)
            Constructor cons2 = Integer.class.getConstructor(String.class);
            Integer n2 = (Integer) cons2.newInstance("456");
            System.out.println(n2);

            Constructor<Person> p = Person.class.getConstructor(String.class);
            Person person = p.newInstance("jack");
            System.out.println(person.name);
        } catch (NoSuchMethodException | InstantiationException | InvocationTargetException |
                 IllegalAccessException exception) {
            System.out.println("getConstructor exception = " + exception.getMessage());
        } finally {
            System.out.println("getConstructor end");
        }
    }

    public static void getSuper() {
        Class i = Integer.class;
        Class n = i.getSuperclass();
        System.out.println(n);
        Class o = n.getSuperclass();
        System.out.println(o);
        System.out.println(o.getSuperclass());

        System.out.println("Integer interfaces");
        Class[] is = i.getInterfaces();
        for (Class cl : is) {
            System.out.println(cl);
        }

        System.out.println("Integer super interfaces");
        Class[] isi = n.getInterfaces();
        for (Class cl : isi) {
            System.out.println(isi);
        }

//        继承关系
//        当我们判断一个实例是否是某个类型时，正常情况下，使用instanceof操作符：
        Object integer = Integer.valueOf(123);
        boolean isDouble = integer instanceof Double; // false
        boolean isInteger = integer instanceof Integer; // true
        boolean isNumber = integer instanceof Number; // true
        boolean isSerializable = integer instanceof java.io.Serializable; // true

//        如果是两个Class实例，要判断一个向上转型是否成立，可以调用isAssignableFrom()：
        // Integer i = ?
        Integer.class.isAssignableFrom(Integer.class); // true，因为Integer可以赋值给Integer
        // Number n = ?
        Number.class.isAssignableFrom(Integer.class); // true，因为Integer可以赋值给Number
        // Object o = ?
        Object.class.isAssignableFrom(Integer.class); // true，因为Integer可以赋值给Object
        // Integer i = ?
        Integer.class.isAssignableFrom(Number.class); // false，因为Number不能赋值给Integer

//        Number.class;
//        Integer.class;
    }

    static class Student extends Person {
        public int score;
        private int grade;

        public Student(String name, int score, int grade) {
            super(name);
            this.score = score;
            this.grade = grade;
        }

        public void hello() {
            System.out.println("Student:hello " + this.name);
        }
    }

    static class Person {
        public String name;

        public Person(String name) {
            this.name = name;
        }

        public void hello() {
            System.out.println("Person:hello " + this.name);
        }
    }
}
